lpunbfandomcom-20200214-history
Seminário Perl 2013/02 (11/0112679, 11/0143035, 11/0118111)
Perl é uma linguagem de programação criada por Larry Wall no meio da década de 80. O nome trata-se de um backronym, isto é, primeiro foi criado o nome Perl e depois as expansões dele. Perl é chamado às vezes de Practical Extraction and Report Language ''embora também possa ser chamado de ''Pathologically Eclectic Rubbish Lister. É uma linguagem open source, isto é, seu código fonte está disponível para todos. Um software grátis podendo ser usado quando e onde quiser sem políticas de licença. Histórico Essa linguagem foi criada quando Larry se deparou com problemas de produção de relatórios. Ele necessitava de algo entre linguagens de baixo nível (difíceis de serem escritas, porém rápidas e ilimitadas) e alto nível (como shell). Logo Perl é uma linguagem de alto nível, rápida e quase ilimitada. Obtendo Perl Em sistemas operacionais como Linux, Mac OS X, Perl já vem pré-instalado. Em outros como Windows é possível optar por distribuições como ActivePerl ou StrawberryPerl. O seu código fonte pode ser escrito num editor de texto de preferência, como bloco de notas. Há também IDE’s que podem ser utilizadas que possuem ferramentas auxiliares para o desenvolvimento, como por exemplo, Padre. CPAN (Comprehensive Perl Archive Network) É um repositório com milhares de módulos para serem usados por qualquer um. Além de exemplos, documentação, extensões para Perl. Os módulos enviados ao CPAN passam por teste automatizados. Um teste conhecido como "Smoke Testing", que dá uma boa segurança de que a aplicação não irá falhar. Além disso, qualquer um que se cadastre poderá também mandar o seu módulo. Aqui se encontra o link para o buscador do CPAN. Tipos de Dados Perl se baseia em três tipos básicos de dados, são eles: escalares, vetores de escalares e hashes de escalares. A linguagem segue a linha da tipagem fraca, isto é, não é preciso declarar um tipo para os dados básicos e ainda pode mudar dependendo do contexto. Isso ficará claro no detalhamento de cada um deles. 'Escalares' Um escalar é indicado pelo cifrão ($). Pode ser um número inteiro, número de ponto flutuante, string, ''entre outros. Exemplos de declarações: $escalarInteiro = 42; #Um inteiro $escalarFloat = 3.1415; #Um Numero de ponto flutuante $numeroAvocado = 6.02e23; #Notação científica $stringInterpolada = “O numero pi = $escalarFloat”; #String com interpolação $stringValor = 'O valor da passagem é R$2,00'; #String sem interpolação Se o valor não deixa explícito o valor da sua variável no momento de sua declaração, ela é automaticamente recebe um valor '''undef. '''Esse valor pode ser zero (0) ou null, como já dito depende do contexto. Agora um exemplo básico que deixa claro o quanto o contexto é importante em Perl: #!/usr/bin/perl '''my '$number = "555"; #$number nesse contexto é uma string print $number + 111, "\n"; #$number é convertido para número para ser somado com o valor 111, logo o valor imprimido na saída padrão é 666 Algumas considerações acerca do uso de strings O uso de strings em Perl é algo essencial, logo é importante estar ciente dos seus diversos usos. Só precisamos lembrar de um de seus acrônimos: Practical Extraction and Report Language. Uso de aspas simples ou duplas: Como já visto antes, usando aspas duplas Perl subentende que você deseja interpolar algum valor, que pode vir de um escalar, por exemplo: #!/usr/bin/perl my '''$numero = 555; print “O valor do numero = $numero\n”; # A saída padrão será “O valor do numero = 555” print ‘O valor do numero = $numero’; # A saída padrão será “O valor do numero = $numero” '''Uso de escapes: Em alguns casos necessitamos de uso de caracteres como o arroba (@) em um e-mail, por exemplo, ou o cifrão ($) para citar valores de dinheiro, etc. Se for usado com aspas duplas haverá um erro, pois o Perl entenderá que você deseja interpolar algum valor, logo você poderá usar a barra invertida (\) como escape, segue um exemplo: #!/usr/bin/perl print “meu e-mail eh lp\@unb.br”; # A saída será “meu e-mail é lp@unb.br” print “Isso eh uma barra invertida \\”; #Se quisermos mostrar uma barra invertida temos que escapá-la também, senão a segunda aspa dupla seria ignorada e haveria um erro. A saída é “Isso eh uma barra invertida \” 'Vetores' Vetores são indicados pelo arroba (@). São uma sequência de elementos que podem ser acessados por um índice. Muito semelhante aos vetores presentes em linguagens como C ou Java. Logo nesses vetores temos uma lista de strings, números inteiros ou qualquer outro escalar. Exemplo de declarações: @vetordeNumeros = (1,2,3,4,5); @vetordeStrings = ("Charles", "Victor", "Gabriel"); @vetordeTudo = (1, "LP", 2.3); @vetordeVetor = (1,2,3, 4,5,6, 7,8,9); Acessando e modificando elementos no vetor Como cada elemento do vetor representa um escalar o acesso é feito a partir do símbolo do cifrão ($) explicitando qual o índice desejado. É válido lembrar que assim como em linguagem C, o índice começa com o inteiro zero (0). Veja o exemplo a seguir: #!/usr/bin/perl @vetordeTudo = (1, "LP", 2.3); print $vetordeTudo1."\n"; # Imprimindo na saída padrão o elemento 1 do vetor, isto é, a string “LP” $vetordeTudo1 = "Linguagens de Programacao"; # Essa atribuição modifica o valor da posição 1 do vetor para a string “Linguagens de Programacao” $vetordeTudo5 = "Estou com sono"; # Atribui a string “Estou com sono” ao vetor print $vetordeTudo5."\n"; #Imprime na tela o valor da posição 5 da string print $vetordeTudo4."\n"; #Não imprime nada na tela Esse exemplo mostra que o vetor que você declarou não possui um tamanho definido. Na declaração havia sido colocado apenas 3 elementos no vetor, isto é, posições 0,1 e 2. E no decorrer do código fizemos uma atribuição de um valor para a posição 5 o que funciona perfeitamente. Porém, como não fizemos o mesmo para a posição 4 do vetor, essa região permanece como undef. Após essa atribuição o valor do tamanho do vetor aumenta de três (3) para seis (6). No exemplo abaixo, acessando um vetor de vetores: #!/usr/bin/perl @vetordeVetor = (1,2,3, 4,5,6, 7,8,9); print $vetordeVetor11; #Imprime o valor 5 que está na posição 1 do vetor que está na posição 1 Algumas operações com vetores: Abaixo temos um exemplo com algumas funções simples para operar com vetores, cada uma possui um comentário explicativo, e abaixo disso o resultado de todas as impressões: #!/usr/bin/perl # Criamos um novo vetor com alguns valores @disciplinas = ("LP","POO","CB"); print "1. \@disciplinas = @disciplinas\n"; # A função push irá inserir um elemento no final do vetor push(@disciplinas, "ED"); print "2. \@disciplinas = @disciplinas\n"; # A função unshift adiciona um elemento no inicio do vetor unshift(@disciplinas, "SD1"); print "3. \@disciplinas = @disciplinas\n"; # A função pop remove um elemento do final do vetor pop(@disciplinas); print "4. \@disciplinas = @disciplinas\n"; # A função shift remove um elemento no inicio do vetor shift(@disciplinas); print "5. \@disciplinas = @disciplinas\n"; # E por fim fazemos uma ordenação desse vetor usando a função sort @disciplinas = sort(@disciplinas); print "6. \@disciplinas = @disciplinas\n"; Saída: 1. @disciplinas = LP POO CB 2. @disciplinas = LP POO CB ED 3. @disciplinas = SD1 LP POO CB ED 4. @disciplinas = SD1 LP POO CB 5. @disciplinas = LP POO CB 6. @disciplinas = CB LP POO Hashes Também conhecidos como vetores associativos, 'são um tipo de dados onde cada valor é associado a uma chave. Diferente dos vetores que acessam os valores de cada posição por um inteiro nos ''hashes isso é feito por um escalar qualquer (mas essas chaves sempre serão convertidas para strings). Veja a imagem ao lado, onde se compara um '''hash '''com um '''vetor onde o cabeçalho em azul indica o índice no vetor e a chave no hash: Exemplos de declarações: %longday = ("Sun", "Sunday", "Mon", "Monday", "Tue", "Tuesday", "Wed", "Wednesday", "Thu", "Thursday", "Fri", "Friday", "Sat", "Saturday"); # A primeira é a chave e a segunda seu valor e assim sucessivamente, isto é, “Sun” é a chave de “Sunday” e “Mon” é a chave de “Monday” %longday = ("Sun" => "Sunday", "Mon" => "Monday", "Tue" => "Tuesday", "Wed"=> "Wednesday", "Thu" => "Thursday", "Fri" => "Friday", "Sat" => "Saturday"); # O mesmo hash anterior, porém uma forma mais legível de declará-lo, onde a chave tem uma “seta” igual e maior (=>) apontando para seu valor %vazio; #Um hash iniciado vazio %hashdeVetores = (1 => 1,2,3, 2 => 4,5,6, 3=> 7,8,9); %hashdeHash = (CIC => { LP => "Ladeira", CB => "Zaghetto", }, MAT => { C1 => "Dimas", C3 => "Nilton", } ); Acessando e modificando hashes: O acesso ao hash é feito a partir da sua chave que são colocadas entre chaves ({}), veja o exemplo: #!usr/bin/perl %areas = (1 => "Exatas", 2 => "Humanas", 3 => "Biologicas"); print $areas{"1"}, "\n"; # Imprimirá na saída padrão o valor "Exatas" print $areas{'2'}, "\n"; # Imprimirá na saída padrão o valor "Humanas" print $areas{3}; # Imprimirá na saída padrão o valor "Biologicas" $areas{3} = "Humanas"; # Agora a chave 3 possui o valor "Humanas" $areas{2} = "Biologicas"; # E a chave 2 possui o valor "Biologicas" print $areas{'2'}, "\n"; # Agora isso imprimirá "Biologicas" print $areas{3}; # E aqui imprimirá "Humanas" Algo que é notável nesse exemplo é a maneira de passar o valor da chave. Como dito anteriormente, Perl sempre converterá a chave para uma string. Logo para acessar um valor de um hash você pode passar a chave tanto como foi declarada quanto como uma string usando aspas simples ou duplas. Repare também que usamos o cifrão ($) pois estamos nos referindo a um escalar quando estamos acessando através da chave. Agora um exemplo com Hash de vetores e Hash de hashes: #!/usr/bin/perl %hashdeVetor = (1 => 1,2,3, 2 => 4,5,6, 3=> 7,8,9); %hashdeHashes = (CIC => { LP => "Ladeira", CB => "Zaghetto", }, MAT => { C1 => "Dimas", C3 => "Nilton", } ); print $hashdeVetor{1}0, "\n"; #O primeiro parâmetro se refere a chave do hash, isto é, o vetor 1,2,3 e o segundo se refere a posição no caso 0 que é o valor 1 print $hashdeHashes{MAT}{C3}, "\n"; #O primeiro parâmetro se refere a chave do hash exterior, isto é, MAT OU CIC. Nesse caso MAT. E o segundo se refere a chave do hash interior no caso C3 que é a chave para o valor "Nilton" Arquivos Manipular arquivos em Perl é algo simples e se faz através de filehandles, ou seja identificadores de arquivos, que atribuem um nome interno ao programa a um arquivo físico. Todo filehandle tem capacidade de operar leitura e escrita sobre eles e ainda possuem a capacidade de adicionar um modo de fazer isto. 'Abrindo um Arquivo' Existem 2 formas de se realizar isto: 'Função Open' open(ARQUIVO, " Apenas leitura > ou w Cria,Escreve e Trunca >> ou a Escreve, Junta e Cria +< ou r+ Lê e Escreve +> ou w+ Lê, Escreve,Cria e Trunca +>> ou a+ Lê, Escreve, Junta e Cria 'Função Sysopen' Sysopen() funciona de modo similar à open(), exceto pelo fato de que o modo e o nome do arquivo funcinam em separado. sysopen(DATA, "file.txt", O_RDWR|O_TRUNC ); Neste caso o modo de abertura, se encontra no terceiro parâmetro e é dado por expressões pré-definidas: O_RDWR Read and Write O_RDONLY Read Only O_WRONLY Write Only O_CREAT Create the file O_APPEND Append the file O_TRUNC Truncate the file O_EXCL Stops if file already exists O_NONBLOCK Non-Blocking usability 'Fechando Arquivos' Para fechar arquivos, utilizamos a função close(FILEHANDLE) e ao fazer isso, limpa-se o buffer do FILEHANDLE e fecha o descritor de arquivos do sistema. Se nenhum argumento for especificado, então FILEHANDLE assume por default o arquivo sendo usado mais recentemente. close(ARQUIVO); 'Lendo e Escrevendo em Arquivos' Existem muitas formas de se ler e escrever em um arquivo: 'Operador ' Esse é o principal método usado. Em um contexto escalar, ele recebe uma linha do filehandle. #!/usr/bin/perl print "What is your name?\n"; $nome = ; print "Hello $name\n"; Em um contexto de lista, cada nó recebe uma linha. #!/usr/bin/perl open(DATA,"; close(DATA); 'Função getc()' Esta função retorna um único caracter contido no filehandle em seus parâmetros ou em caso nenhum seja especificado. #retorna um caracter de ARQUIVO getc(ARQUIVO); 'Função read()' Baseicamente, a função pode ser lida como: read FILEHANDLE, SCALAR, LENGTH, OFFSET Onde FILEHANDLE é o filehandle a ser especificado, SCALAR é a variável que receberá a string, LENGTH é o tamanho da string a ser lida e OFFSET determina quantos bytes de espaço deve ser "pulado" em SCALAR antes de armazenar a string lida. Por default, OFFSET é zero. 'Função print()' print FILEHANDLE LIST Imprime os dados coletados em LIST em FILEHANDLE, este por default é . print "Hello World\n" 'Posicionamento dentro de um Arquivo' Para isto necessita-se das funções tell() e seek(). 'Função Tell()' Informa a posição atual dentro do filehandle especificado. tell ARQUIVO; 'Função Seek()' Posiciona o ponteiro do arquivo e FILEHANDLE na posição contida em bytes em POSITION e referencial contido em WHENCE,isto é, se começa a contagem a partir do início, do fim ou da posição atual do arquivo. seek FILEHANDLE, POSITION, WHENCE seek DATA, 256, 0; 'Informações contidas no Arquivo' Pode-se realizar alguns testes para verificar certas características de um arquivo. Estes sao chamados de '-X tests'. Alguns exemplos são: -A Age of file (at script startup) in days since modification. -B Is it a binary file? -C Age of file (at script startup) in days since modification. -M Age of file (at script startup) in days since modification. -O Is the file owned by the real user ID? -R Is the file readable by the real user ID or real group? -S Is the file a socket? -T Is it a text file? -W Is the file writable by the real user ID or real group? -X Is the file executable by the real user ID or real group? -b Is it a block special file? -c Is it a character special file? -d Is the file a directory? -e Does the file exist? -f Is it a plain file? -g Does the file have the setgid bit set? -k Does the file have the sticky bit set? -l Is the file a symbolic link? -o Is the file owned by the effective user ID? -p Is the file a named pipe? -r Is the file readable by the effective user or group ID? -s Returns the size of the file, zero size = empty file. -t Is the filehandle opened by a TTY (terminal)? -u Does the file have the setuid bit set? -w Is the file writable by the effective user or group ID? -x Is the file executable by the effective user or group ID? -z Is the file size zero? Um pequeno exemplo de sua usabilidade: my $file = "/usr/test/file1.txt"; my (@description, $size); if (-e $file){ push @description, 'binary' if (-B _); push @description, 'a socket' if (-S _); push @description, 'a text file' if (-T _); push @description, 'a block special file' if (-b _); push @description, 'a character special file' if (-c _); push @description, 'a directory' if (-d _); push @description, 'executable' if (-x _); push @description, (($size = -s _)) ? "$size bytes" : 'empty'; print "$file is ", join(', ',@description),"\n"; } 'Outras operações' Abaixo, segue-se um código com possíveis operações em Perl. # Abrindo arquivo para leitura open(ARQUIVO1, "arquivo2.txt"); # Copy data from one file to another. while(){ print DATA2 $_; } #Renomeando arquivo1.txt por file1.txt rename ("/usr/test/arquivo1.txt", "/usr/test/file1.txt" ); #Deletando file1.txt unlink ("/usr/test/file1.txt"); close( ARQUIVO1 ); close( ARQUIVO2 ); Formatação Perl é muito usado para construção de relatórios, portanto ela possui mecanismos que ajudam na produção dos mesmos. Por isso, iremos falar sobre a formatação, isto é, definindo um formato específico, de um arquivo. Para isso, usa-se o template format. ' 'Definindo um formato format PESSOA = @<<<<<<<<<<<<<<<<<<<<<< @<< $nome $idade @#####.## $salario . Nesse caso, PESSOA é o nome do formato. @<< e @####.## são chamados de fieldline 'e são responsáveis por atribuir o formato da linha. Termina-se a descrição do formato através de um ponto final. O número de espaços é determinado pelo númmero de @ e < e #, ou seja, @<< seria representado por 3 caracteres e seria preenchido por $idade. A seguir uma tabela com os tipos de justificação dos textos: @>>>> justificado pela direita @<<<< justificado pela esquerda @|||| centralizado @####.## campo numérico fixo @* campo de múltiplas linhas fixo 'Usando o formato Para escrever nesse formato, normalmente poderia utilizar 'write FORMAT', mas isso implicaria que o nome do arquivo em que se escreveria também seria chamado de FORMAT. Mas se quisermos enviar esses dados para STDOUT devemos utilizar a função select() e entao associamos PESSOA a STDOUT criando um novo formato usando a variável especial $~ ou $FORMAT_NAME.Agora quando fizermos um write(), os dados serão enviados para STDOUT.Abaixo, segue-se um exemplo: #!/usr/bin/perl format PESSOA = @<<<<<<<<<<<<<<<<<<<<<< @<< $nome $idade @#####.## $salario . select(STDOUT); $~ = PESSOA; @n = ("Victor", "Charles", "Gabriel"); @i = (18,19, 19); @s = (2000.00, 2500.00, 4000.000); $j = 0; foreach (@n){ $nome = $_$_; $idade = $i$j; $salario = $s$j++ write; } E isso resulta em: Victor 20 2000.00 Charles 19 2500.00 Gabriel 19 4000.00 Obs:Se pretende-se escrever seu relatório em qualquer outro identificador de arquivo diferente de STDOUT, pode-se utilizar select() para selecionar este identificador de arquivo e o resto da lógica permanece inalterado. 'Mais Formatações do Relatório' O cabeçalho aparecerá no topo de cada página e é muito simples de se produzir. Para isto, crie um outro formato, preferencialmente, com nome parecido com o do formato a ser usado, e em seguida, instancie ele na variável especial $^ ou $FORMAT_TOP_NAME. Ainda, pode-se adicionar a paginação, o número de linhas por página, o rodapé. Para isto faremos uso de mais algumas variáveis especiais: *$% ou $FORMAT_PAGE_NUMBER, recebe a página atual. *$= ou $FORMAT_LINES_PER_PAGE , recebe o número de linhas em uma página, por default, $= é 60. *$- ou $FORMAT_LINES_LEFT, adiciona o footer da mesma maneira que o Cabeçalho. Abaixo, tem-se um exemplo de um código utilizando algumas formatações adicionais: #!/usr/bin/perl #formatação dos dados format PESSOA = @<<<<<<<<<<<<<<<<<<<<<< @<< $nome $idade @#####.## $salario . #formatação do cabeçalho format PESSOA_TOP = Nome Idade Pagina @< $% . #formatação do rodapé format PESSOA_BOTTOM = End of Page @< $% . select(STDOUT); $~ = PESSOA; $^ = PESSOA_TOP; $- = PESSOA_BOTTOM; @n = ("Victor", "Charles", "Gabriel"); @i = (18,19, 19); @s = (2000.00, 2500.00, 4000.000); $j = 0; foreach (@n){ $nome = $_$_; $idade = $i$j; $salario = $s$j++ write; }